home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / indent / parse.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-04-06  |  8.8 KB  |  334 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * Copyright (c) 1976 Board of Trustees of the University of Illinois.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted
  7.  * provided that this notice is preserved and that due credit is given
  8.  * to the University of California at Berkeley and the University of
  9.  * Illinois at Urbana.  The name of either University may not be used
  10.  * to endorse or promote products derived from this software without
  11.  * specific prior written permission. This software is provided
  12.  * ``as is'' without express or implied warranty.
  13.  */
  14.  
  15. #ifndef lint
  16. static char sccsid[] = "@(#)parse.c    5.5 (Berkeley) 3/22/88";
  17. #endif /* not lint */
  18.  
  19. /*
  20.  * FILE NAME:
  21.  *    parse.c
  22.  *
  23.  * PURPOSE:
  24.  *    Contains the routines which keep track of the parse stack.
  25.  *
  26.  * GLOBALS:
  27.  *    ps.p_stack =    The parse stack, set by both routines
  28.  *    ps.il =        Stack of indentation levels, set by parse
  29.  *    ps.cstk =        Stack of case statement indentation levels, set by parse
  30.  *    ps.tos =        Pointer to top of stack, set by both routines.
  31.  *
  32.  * FUNCTIONS:
  33.  *    parse
  34.  *    reduce
  35.  */
  36. /*-
  37.  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois 
  38.  *
  39.  * All rights reserved 
  40.  *
  41.  *
  42.  * NAME: parse 
  43.  *
  44.  * FUNCTION: Parse is given one input which is a "maxi token" just scanned
  45.  * from input.  Maxi tokens are signifigant constructs such as else, {,
  46.  * do, if (...), etc.  Parse works with reduce to maintain a parse stack
  47.  * of these constructs.  Parse is responsible for the "shift" portion of
  48.  * the parse algorithm, and reduce handles the "reduce" portion. 
  49.  *
  50.  * HISTORY: initial coding     November 1976    D A Willcox of CAC 
  51.  *
  52.  */
  53.  
  54. #include "./indent_globs.h"
  55. #include "./indent_codes.h"
  56.  
  57.  
  58.  
  59.  
  60. parse(tk)
  61.     int         tk;        /* the code for the construct scanned */
  62. {
  63.     int         i;
  64.  
  65. #ifdef debug
  66.     printf("%2d - %s\n", tk, token);
  67. #endif
  68.     while (ps.p_stack[ps.tos] == ifhead && tk != elselit) {
  69.     /* true if we have an if without an else */
  70.     ps.p_stack[ps.tos] = stmt;    /* apply the if(..) stmt ::= stmt
  71.                  * reduction */
  72.     reduce();        /* see if this allows any reduction */
  73.     }
  74.  
  75.  
  76.     switch (tk) {        /* go on and figure out what to do with
  77.                  * the input */
  78.  
  79.     case decl:         /* scanned a declaration word */
  80.         ps.search_brace = btype_2;
  81.         /* indicate that following brace should be on same line */
  82.         if (ps.p_stack[ps.tos] != decl) {    /* only put one declaration onto
  83.                      * stack */
  84.         break_comma = true;    /* while in declaration, newline
  85.                      * should be forced after comma */
  86.         ps.p_stack[++ps.tos] = decl;
  87.         ps.il[ps.tos] = ps.i_l_follow;
  88.  
  89.         if (ps.ljust_decl) {    /* only do if we want left
  90.                      * justified declarations */
  91.             ps.ind_level = 0;
  92.             for (i = ps.tos - 1; i > 0; --i)
  93.             if (ps.p_stack[i] == decl)
  94.                 ++ps.ind_level;    /* indentation is number
  95.                          * of declaration levels
  96.                          * deep we are */
  97.             ps.i_l_follow = ps.ind_level;
  98.         }
  99.         }
  100.         break;
  101.  
  102.     case ifstmt:         /* scanned if (...) */
  103.         if (ps.p_stack[ps.tos] == elsehead && ps.else_if)    /* "else if ..." */
  104.         ps.i_l_follow = ps.il[ps.tos];
  105.     case dolit:         /* 'do' */
  106.     case forstmt:         /* for (...) */
  107.         ps.p_stack[++ps.tos] = tk;
  108.         ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
  109.         ++ps.i_l_follow;    /* subsequent statements should be
  110.                  * indented 1 */
  111.         ps.search_brace = btype_2;
  112.         break;
  113.  
  114.     case lbrace:         /* scanned { */
  115.         break_comma = false;/* don't break comma in an initial list */
  116.         if (ps.p_stack[ps.tos] == stmt || ps.p_stack[ps.tos] == decl
  117.             || ps.p_stack[ps.tos] == stmtl)
  118.         ++ps.i_l_follow;    /* it is a random, isolated stmt group or
  119.                  * a declaration */
  120.         else {
  121.         if (s_code == e_code) {
  122.             /* only do this if there is nothing on the line */
  123.             --ps.ind_level;
  124.             /* it is a group as part of a while, for, etc. */
  125.             if (ps.p_stack[ps.tos] == swstmt && ps.case_indent)
  126.             --ps.ind_level;
  127.             /*
  128.              * for a switch, brace should be two levels out from
  129.              * the code 
  130.              */
  131.         }
  132.         }
  133.  
  134.         ps.p_stack[++ps.tos] = lbrace;
  135.         ps.il[ps.tos] = ps.ind_level;
  136.         ps.p_stack[++ps.tos] = stmt;
  137.         /* allow null stmt between braces */
  138.         ps.il[ps.tos] = ps.i_l_follow;
  139.         break;
  140.  
  141.     case whilestmt:     /* scanned while (...) */
  142.         if (ps.p_stack[ps.tos] == dohead) {
  143.         /* it is matched with do stmt */
  144.         ps.ind_level = ps.i_l_follow = ps.il[ps.tos];
  145.         ps.p_stack[++ps.tos] = whilestmt;
  146.         ps.il[ps.tos] = ps.ind_level = ps.i_l_follow;
  147.         }
  148.         else {        /* it is a while loop */
  149.         ps.p_stack[++ps.tos] = whilestmt;
  150.         ps.il[ps.tos] = ps.i_l_follow;
  151.         ++ps.i_l_follow;
  152.         ps.search_brace = btype_2;
  153.         }
  154.  
  155.         break;
  156.  
  157.     case elselit:         /* scanned an else */
  158.  
  159.         if (ps.p_stack[ps.tos] != ifhead)
  160.         diag(1,"Unmatched 'else'");
  161.         else {
  162.         ps.ind_level = ps.il[ps.tos];        /* indentation for else should be same as for if */
  163.         ps.i_l_follow = ps.ind_level + 1;    /* everything following should be in 1 level */
  164.         ps.p_stack[ps.tos] = elsehead;
  165.         /* remember if with else */
  166.         ps.search_brace = btype_2;
  167.         }
  168.  
  169.         break;
  170.  
  171.     case rbrace:         /* scanned a } */
  172.         /* stack should have <lbrace> <stmt> or <lbrace> <stmtl> */
  173.         if (ps.p_stack[ps.tos - 1] == lbrace) {
  174.         ps.ind_level = ps.i_l_follow = ps.il[--ps.tos];
  175.         ps.p_stack[ps.tos] = stmt;
  176.         }
  177.         else
  178.         diag(1,"Stmt nesting error.");
  179.         break;
  180.  
  181.     case swstmt:         /* had switch (...) */
  182.         ps.p_stack[++ps.tos] = swstmt;
  183.         ps.cstk[ps.tos] = case_ind;
  184.         /* save current case indent level */
  185.         ps.il[ps.tos] = ps.i_l_follow;
  186.         case_ind = ps.i_l_follow + ps.case_indent;    /* cases should be one
  187.                              * level down from
  188.                              * switch */
  189.         ps.i_l_follow += ps.case_indent + 1;    /* statements should be
  190.                          * two levels in */
  191.         ps.search_brace = btype_2;
  192.         break;
  193.  
  194.     case semicolon:     /* this indicates a simple stmt */
  195.         break_comma = false;/* turn off flag to break after commas in
  196.                  * a declaration */
  197.         ps.p_stack[++ps.tos] = stmt;
  198.         ps.il[ps.tos] = ps.ind_level;
  199.         break;
  200.  
  201.     default:         /* this is an error */
  202.         diag(1,"Unknown code to parser");
  203.         return;
  204.  
  205.  
  206.     }                /* end of switch */
  207.  
  208.     reduce();            /* see if any reduction can be done */
  209. #ifdef debug
  210.     for (i = 1; i <= ps.tos; ++i)
  211.     printf("(%d %d)", ps.p_stack[i], ps.il[i]);
  212.     printf("\n");
  213. #endif
  214.     return;
  215. }
  216. /* 
  217.  * Copyright (C) 1976 by the Board of Trustees of the University of Illinois 
  218.  *
  219.  * All rights reserved 
  220.  *
  221.  *
  222.  * NAME: reduce 
  223.  *
  224.  * FUNCTION: Implements the reduce part of the parsing algorithm 
  225.  *
  226.  * ALGORITHM: The following reductions are done.  Reductions are repeated
  227.  * until no more are possible. 
  228.  *
  229.  * Old TOS        New TOS <stmt> <stmt>    <stmtl> <stmtl> <stmt>    <stmtl> do
  230.  * <stmt>    "dostmt" if <stmt>    "ifstmt" switch <stmt>    <stmt>
  231.  * decl <stmt>    <stmt> "ifelse" <stmt>    <stmt> for <stmt>    <stmt>
  232.  * while <stmt>    <stmt> "dostmt" while    <stmt> 
  233.  *
  234.  * On each reduction, ps.i_l_follow (the indentation for the following line) is
  235.  * set to the indentation level associated with the old TOS. 
  236.  *
  237.  * PARAMETERS: None 
  238.  *
  239.  * RETURNS: Nothing 
  240.  *
  241.  * GLOBALS: ps.cstk ps.i_l_follow = ps.il ps.p_stack = ps.tos = 
  242.  *
  243.  * CALLS: None 
  244.  *
  245.  * CALLED BY: parse 
  246.  *
  247.  * HISTORY: initial coding     November 1976    D A Willcox of CAC 
  248.  *
  249.  */
  250. /*----------------------------------------------*\
  251.  * |   REDUCTION PHASE
  252. \*----------------------------------------------*/
  253. reduce() {
  254.  
  255.     register int i;
  256.  
  257.     for (;;) {            /* keep looping until there is nothing
  258.                  * left to reduce */
  259.  
  260.     switch (ps.p_stack[ps.tos]) {
  261.  
  262.         case stmt: 
  263.         switch (ps.p_stack[ps.tos - 1]) {
  264.  
  265.             case stmt: 
  266.             case stmtl: 
  267.             /* stmtl stmt or stmt stmt */
  268.             ps.p_stack[--ps.tos] = stmtl;
  269.             break;
  270.  
  271.             case dolit: /* <do> <stmt> */
  272.             ps.p_stack[--ps.tos] = dohead;
  273.             ps.i_l_follow = ps.il[ps.tos];
  274.             break;
  275.  
  276.             case ifstmt: 
  277.             /* <if> <stmt> */
  278.             ps.p_stack[--ps.tos] = ifhead;
  279.             for (i = ps.tos - 1;
  280.                 (
  281.                     ps.p_stack[i] != stmt
  282.                     &&
  283.                     ps.p_stack[i] != stmtl
  284.                     &&
  285.                     ps.p_stack[i] != lbrace
  286.                 );
  287.                 --i);
  288.             ps.i_l_follow = ps.il[i];
  289.             /*
  290.              * for the time being, we will assume that there
  291.              * is no else on this if, and set the indentation
  292.              * level accordingly. If an else is scanned, it
  293.              * will be fixed up later 
  294.              */
  295.             break;
  296.  
  297.             case swstmt: 
  298.             /* <switch> <stmt> */
  299.             case_ind = ps.cstk[ps.tos - 1];
  300.  
  301.             case decl:     /* finish of a declaration */
  302.             case elsehead: 
  303.             /* <<if> <stmt> else> <stmt> */
  304.             case forstmt: 
  305.             /* <for> <stmt> */
  306.             case whilestmt: 
  307.             /* <while> <stmt> */
  308.             ps.p_stack[--ps.tos] = stmt;
  309.             ps.i_l_follow = ps.il[ps.tos];
  310.             break;
  311.  
  312.             default:     /* <anything else> <stmt> */
  313.             return;
  314.  
  315.         }        /* end of section for <stmt> on top of
  316.                  * stack */
  317.         break;
  318.  
  319.         case whilestmt:     /* while (...) on top */
  320.         if (ps.p_stack[ps.tos - 1] == dohead) {
  321.             /* it is termination of a do while */
  322.             ps.p_stack[--ps.tos] = stmt;
  323.             break;
  324.         }
  325.         else
  326.             return;
  327.  
  328.         default:         /* anything else on top */
  329.         return;
  330.  
  331.     }
  332.     }
  333. }
  334.